import socket, random, mathutils, math
from bge import logic,events,render


toucheRelache = logic.KX_INPUT_JUST_RELEASED
toucheActive = logic.KX_INPUT_JUST_ACTIVATED #racourcis comprehensibles des etats du clavier
toucheEnfonce = logic.KX_INPUT_ACTIVE

class Vue:
	def __init__(self, controleur):
		self.controleur = controleur

		self.cleEnCours = dict() #conteneur des cles, pas encore utilise
		self.visualisationDict = dict() #declaration du dictionnaire des objets visuels et de leur nom; format {nomObjetVisuel:objetVisuel}
		#render.showMouse(1)
		render.setMousePosition(int (render.getWindowWidth()/2), int(render.getWindowHeight()/2))

	def activerHUD(self):
		logic.addScene("HUD",1)

	def changerCouleur(self, nomObjet, couleur):
		if nomObjet in self.visualisationDict.keys():
			objetVisuel = self.visualisationDict[nomObjet]
			mesh = objetVisuel.meshes[0]
			for mat in range(mesh.numMaterials): #pour tous les materiels
				for v_index in range(mesh.getVertexArrayLength(mat)): #pour tous les vertex
					vertex = mesh.getVertex(mat, v_index) #on prend un vertexProxy (il me semble)
					vertex.color = couleur
		else:
			print("VUE: Impossible de changer la couleur de l'objet " + str(nomObjet) + ", il n'existe pas.")

	def updateHUD(self, vie, nbrBallePistolet, nbrBalleMp78, nbrEnergie, nbrMetal):
		sceneHud = logic.getSceneList()
		sceneHud[1].objects['Vie'].text = str(vie) 
		sceneHud[1].objects['NbrBallePistolet'].text = str(nbrBallePistolet) 
		sceneHud[1].objects['NbrBalleMp78'].text = str(nbrBalleMp78)
		sceneHud[1].objects['NbrEnergie'].text = str(nbrEnergie)
		sceneHud[1].objects['NbrMetal'].text = str(nbrMetal)

	def changerArme(self,nomJoueur,numArme):
		scene = logic.getCurrentScene()
		couteau = scene.objects[nomJoueur+".Couteau"]
		pistolet = scene.objects[nomJoueur+".Pistolet"]
		mp78 = scene.objects[nomJoueur+".Mp78"]
		couteau.setVisible(False,False)
		pistolet.setVisible(False,False)
		mp78.setVisible(False,False)

		if numArme == 2:
			couteau.setVisible(True,False)
		elif numArme == 3:
			pistolet.setVisible(True,False)
			print("Arme:" +str(numArme))
		elif numArme == 4:
			mp78.setVisible(True,False)

	def creerObjet(self, nomObjet, typeObj, position, scale=[1,1,1], layer=1, rotation=0):
		scene = logic.getCurrentScene()
		spawner = scene.objects["Spawner" + str(layer)] #brique de depart

		nouvelObjet = scene.addObject(typeObj, spawner) #prends pour acquis que le typeObj est valide...
		if scale == [1,1,1]:
			ObjScale = scene.objects[typeObj].localScale
		else:
			ObjScale = scale

		nouvelObjet.localScale = ObjScale
		nouvelObjet.localPosition = position
		

		self.visualisationDict.update({nomObjet:nouvelObjet}) #ajout au dictionnaire
		if rotation is not 0:
			self.tournerObjet(nomObjet, rotation)

		#print("VUE: Ajout de l'objet " + str(nomObjet) + ", de type " + str(typeObj) + " a la position " + str(position))

	def creerJoueur(self, nomObjet, typeObj, position, layer=1, rotation=0):
		scene = logic.getCurrentScene()
		spawner = scene.objects["Spawner" + str(layer)] # vas chercher le spawner du layer voullu
		cont = logic.getCurrentController()
		own = cont.owner
	
		nouveauJoueur = scene.addObject(typeObj , spawner)  # spawner de reference, pour trouver le layer

		ObjScale = scene.objects[typeObj].localScale
		nouveauJoueur.localScale = ObjScale # grosseur predefini
		nouveauJoueur.localPosition = position

		self.visualisationDict.update({nomObjet:nouveauJoueur}) #ajout au dictionnaire
		#print("VUE: Ajout de l'objet " + str(nomObjet) + ", de type " + str(typeObj) + " a la position " + str(position))
		#print("Avec la rotation suivante",nouveauJoueur.localOrientation.to_euler('XYZ'))
		
		if nomObjet == self.controleur.nomEntite: #le joueur est celui local
			soleil = scene.objects["Sun"]
			soleil.setParent(nouveauJoueur,0,0)
		
		return nouveauJoueur

	def creerLogomate(self, nomObjet, typeObj, position, layer=1, rotation=0):
		scene = logic.getCurrentScene()
		spawner = scene.objects["Spawner" + str(layer)] # vas chercher le spawner du layer voullu
		cont = logic.getCurrentController()
		own = cont.owner
	
		nouveauLogomate = scene.addObject(typeObj , spawner)  # spawner de reference, pour trouver le layer

		ObjScale = scene.objects[typeObj].localScale
		nouveauLogomate.localScale = ObjScale # grosseur predefini
		nouveauLogomate.localPosition = position
		
		self.visualisationDict.update({nomObjet:nouveauLogomate}) #ajout au dictionnaire
		#print("VUE: Ajout de l'objet " + str(nomObjet) + ", de type " + str(typeObj) + " a la position " + str(position))
		return nouveauLogomate
		
	
	def creerGardien(self, nomObjet, typeObj, position, layer=1, rotation=0):
		scene = logic.getCurrentScene()
		spawner = scene.objects["Spawner" + str(layer)] # vas chercher le spawner du layer voullu
		cont = logic.getCurrentController()
		own = cont.owner
	
		nouveauGardien = scene.addObject(typeObj , spawner)  # spawner de reference, pour trouver le layer

		ObjScale = scene.objects[typeObj].localScale
		nouveauGardien.localScale = ObjScale # grosseur predefini
		nouveauGardien.localPosition = position

		#nomCamera = nouveauJoueur.name + ".TPSCamera" # cherche le nom de la camera
		#objectCam = scene.objects[nomCamera]  # selectionner la camera
		#objectCam.setParent(nouveauJoueur)
		#scene.active_camera = objectCam # rendre la vu du joueur a ca camera

		#nomNom = nomObjet + ".Nom" # cherche le nom du joueur
		#nouveauJoueur.children[nomNom]["Text"]   #met le nom du joueur sur ca tete
		self.visualisationDict.update({nomObjet:nouveauGardien}) #ajout au dictionnaire
		#print("VUE: Ajout de l'objet " + str(nomObjet) + ", de type " + str(typeObj) + " a la position " + str(position))
		#print("Avec la rotation suivante",nouveauGardien.localOrientation.to_euler('XYZ'))
		return nouveauGardien
	
	def teleporterObjet(self, nomObjet, position):
		if nomObjet in self.visualisationDict.keys(): #si le nom de l'objet est dans le dictionnaire
			objetVisuel = self.visualisationDict[nomObjet] #on va le chercher
			objetVisuel.localPosition = position
		else:
			print("VUE: Teleportation impossible, l'objet " + str(nomObjet) + " n'existe pas!")
			
	def tournerGardien(self, nomObjet, position):
		if nomObjet in self.visualisationDict.keys(): #si le nom de l'objet est dans le dictionnaire
			objetVisuel = self.visualisationDict[nomObjet] #on va le chercher
			if objetVisuel.localPosition[1] - position[1] != 0 or objetVisuel.localPosition[0] - position[0] != 0: # S'il y a changement de position
				vectTo = objetVisuel.getVectTo(position) # Retourne [distance, globalVectorlist[vx, vy, vz], localVectorlist[vx, vy, vz]]
				objetVisuel.alignAxisToVect(vectTo[1], 0, 0.75) # Valeur du vecteurGlobal, axe donc les x, la vitesse de rotation
		else:
			print("VUE: Teleportation impossible, l'objet " + str(nomObjet) + " n'existe pas!")

	def tournerObjet(self, nomObjet, rotation): #applyRotation relative
		if nomObjet in self.visualisationDict.keys(): #si le nom de l'objet est dans le dictionnaire
			objetVisuel = self.visualisationDict[nomObjet] #on va le chercher
			rotation = int(rotation)
			rotation = rotation*(math.pi/180) #conversion en radians
			rotationVue = [0,0, rotation]
			objetVisuel.localOrientation = rotationVue
		else:
			print("VUE: Rotation impossible, l'objet " + str(nomObjet) + " n'existe pas!")		

	def detruireObjet(self, nomObjet):
		if nomObjet in self.visualisationDict.keys():
			objetVisuel = self.visualisationDict[nomObjet] #on va le chercher
			objetVisuel.endObject() #destruction de l'objet visuel
			self.visualisationDict.pop(nomObjet) #destruction de l'objet memoire (dans le dictionnaire)

	def activeCamera(self, nomObjet):
		scene = logic.getCurrentScene()
		cameraTPS = scene.objects[nomObjet + ".TPSCamera"] #met la camera 3ieme personne dans camera
		cameraFPS = scene.objects[nomObjet + ".FPSCamera"] #met la camera 1iere personne dans camera
		
		#pas besoin de faire un enfant de la camera, elle est deja enfant, il ne suffit que de lactiver
		if scene.active_camera == cameraTPS:
			scene.active_camera = cameraFPS #active FPSCamera sur le joueur en particuler.
		else :
			scene.active_camera = cameraTPS #active TPSCamera sur le joueur en particuler.
	
	def creerPorte(self, nomObjet, positionDepart, positionFin, layer=1, rotation=0):
		directionMur = "" # false nord-sud (y) / true est-west(x)

		positionPorte = [0,0,0]
		positionMur2 = [0,0,0]

		differenceX = abs(positionFin[0]) - abs(positionDepart[0])
		differenceY = abs(positionFin[1]) - abs(positionDepart[1]) 
		differenceZ = abs(positionFin[2]) - abs(positionDepart[2])

		if  abs(differenceX) > abs(differenceY): #le mur s'etend sur l'axe des X
			if positionFin[0] > positionDepart[0]:
				positionPorte[0] = positionDepart[0]+(differenceX/2)-1
				positionMur2[0] = positionPorte[0]+2
				scaleX = (differenceX/4) - 0.5
				scaleY = (differenceY/2)
				scaleZ = (differenceZ/2) 

			else:
				positionPorte[0] = positionDepart[0]+(differenceX/2)-1
				positionMur2[0] = positionPorte[0]
				scaleX = (differenceX/4) + 0.5
				scaleY = (differenceY/2)
				scaleZ = (differenceZ/2) 

			if positionFin[1] > positionDepart[1]:
				positionPorte[1] = positionDepart[1] + differenceY/4 
				positionMur2[1] = positionPorte[1]-(scaleY/2)
			else:
				positionPorte[1] = positionDepart[1] + differenceY/4 
				positionMur2[1] = positionPorte[1]-(scaleY/2)
			directionMur = "nord-sud"
			
		else: 	#le mur s'etend sur l'axe des Y								
			 
			if positionFin[1] > positionDepart[1]:
				positionPorte[1] = positionDepart[1]+(differenceY/2)-1
				positionMur2[1] = positionPorte[1]+2
				scaleX = (differenceX/2)
				scaleY = (differenceY/4) - 0.5
				scaleZ = (differenceZ/2)
			else:
				positionPorte[1] = positionDepart[1]+(differenceY/2)-1
				positionMur2[1] = positionPorte[1]
				scaleX = (differenceX/2)
				scaleY = (differenceY/4) + 0.5
				scaleZ = (differenceZ/2)

			if positionFin[0] > positionDepart[0]:
				positionPorte[0] = positionDepart[0] + differenceX/4
				positionMur2[0] = positionPorte[0]-(scaleX/2)
			else:
				positionPorte[0] = positionDepart[0] + differenceX/4 
				positionMur2[0] = positionPorte[0]-(scaleX/2)
			directionMur = "est-west"
			
		positionPorte[2] = positionDepart[2]
		positionMur2[2] = positionDepart[2]

		if directionMur == "nord-sud":

			# Premier mur...
			scene = logic.getCurrentScene()
			spawner = scene.objects["Spawner" + str(layer)]
			mur1 = scene.addObject("Mur", spawner)
			mur1.localScale = [scaleX,scaleY, scaleZ]
			mur1.localPosition = positionDepart

			self.visualisationDict.update({nomObjet:"Mur"})

			#porte...
			scene = logic.getCurrentScene()
			spawner = scene.objects["Spawner" + str(layer)]
			porte = scene.addObject("Porte", spawner)
			porte.localScale = [1,scaleY/2, scaleZ]
			porte.localPosition = positionPorte
			porte.setParent(mur1,0,0)

			#Duexieme mur ...
			scene = logic.getCurrentScene()
			spawner = scene.objects["Spawner" + str(layer)]
			mur2 = scene.addObject("Mur", spawner)
			mur2.localScale = [scaleX,scaleY, scaleZ]
			mur2.localPosition = positionMur2
			mur2.setParent(mur1,0,0)


		elif directionMur =="est-west":

			# Premier mur...
			scene = logic.getCurrentScene()
			spawner = scene.objects["Spawner" + str(layer)]
			mur1 = scene.addObject("Mur", spawner)
			mur1.localScale = [scaleX, scaleY, scaleZ]
			mur1.localPosition = positionDepart

			self.visualisationDict.update({nomObjet:"Mur"})

			#porte...
			scene = logic.getCurrentScene()
			spawner = scene.objects["Spawner" + str(layer)]
			porte = scene.addObject("Porte", spawner)
			porte.localScale = [scaleX/2,1, scaleZ]
			porte.localPosition = positionPorte
			porte.setParent(mur1,0,0)

			#Duexieme mur ...
			scene = logic.getCurrentScene()
			spawner = scene.objects["Spawner" + str(layer)]
			mur2 = scene.addObject("Mur", spawner)
			mur2.localScale = [scaleX, scaleY, scaleZ]
			mur2.localPosition = positionMur2
			mur2.setParent(mur1,0,0)

	def creerCube(self, nomObjet, typeObj, positionDepart, positionFin, layer=1, rotation=0):
			differenceX = abs(positionFin[0]) - abs(positionDepart[0])
			differenceY = abs(positionFin[1]) - abs(positionDepart[1]) 
			differenceZ = abs(positionFin[2]) - abs(positionDepart[2])

			if positionFin[0] > positionDepart[0] :
				scaleX = (differenceX/2)
			else:
				scaleX = (differenceX/2)
			if positionFin[1] > positionDepart[1] :
				scaleY = (differenceY/2)
			else:
				scaleY = (differenceY/2)
			if positionFin[2] > positionDepart[2] :
				scaleZ = (5) #hardcordé, ancienne version: differenceZ/2
			else:
				scaleZ = (5)

			self.creerObjet(nomObjet, typeObj, positionDepart, [scaleX, scaleY, scaleZ], layer, rotation)


	"""Méthode pour déterminer les actions du joueur (par les touches du clavier)"""
	def regarderPourTouches(self):
			keyboard = logic.keyboard
			for keyEvent in keyboard.events:
				if keyboard.events[keyEvent] == toucheEnfonce:
					if keyEvent == events.WKEY:
						self.cleEnCours.update(davancer = 1)
					elif keyEvent == events.SKEY:
						self.cleEnCours.update(dreculer = 1)
					elif keyEvent == events.AKEY:
						self.cleEnCours.update(dlateralG = 1)
					elif keyEvent == events.DKEY:
						self.cleEnCours.update(dlateralD = 1)
					elif keyEvent == events.ONEKEY:
						self.cleEnCours.update(cArme1 = 1)
					elif keyEvent == events.TWOKEY:
						self.cleEnCours.update(cArme2 = 1)
					elif keyEvent == events.THREEKEY:
						self.cleEnCours.update(cArme3 = 1)
					elif keyEvent == events.FOURKEY:
						self.cleEnCours.update(cArme4 = 1)
				elif keyboard.events[keyEvent] == toucheActive:
					if keyEvent == events.CKEY:
						self.activeCamera(self.controleur.nomEntite)
					#elif keyEvent ==events.TKEY:#T pour tester le tir 		
						#self.regarderPourSouris()

				elif keyboard.events[keyEvent] == toucheRelache:
					if keyEvent == events.EKEY:
						scene = logic.getCurrentScene()
						camera = scene.objects[self.controleur.nomEntite + ".FPSCamera"] 
						mire = scene.objects[self.controleur.nomEntite + ".Mire"]
						objetHit = camera.rayCastTo(mire, 50)
						if objetHit != "None":
							for nomObj, obj in self.visualisationDict.items():
								if obj == objetHit:
									self.cleEnCours.update({nomObj:1})
									#self.controleur.modele.pickup(self.controleur.nomEntite, nomObj)
					elif keyEvent == events.PKEY:
						print("Position du joueur: ", self.controleur.modele.entites[self.controleur.nomEntite].position)

	def regarderPourSouris(self):
			MOUSE_UP = 3 #des racourcis vers les states
			MOUSE_HOLD = 2

			mouse = logic.mouse
		
			#définition des boutons: http://www.blender.org/documentation/blender_python_api_2_63_release/bge.events.html#mouse-keys
			if(mouse.events[events.LEFTMOUSE] == MOUSE_HOLD): #la souris est enfoncée
				pass
			elif(mouse.events[events.LEFTMOUSE] == toucheActive): #la souris est activée
				scene = logic.getCurrentScene() #ce bout de code ressemble beaucoup a celui de la lettre E mais le range du rayCast va plus loin
				camera = scene.objects[self.controleur.nomEntite + ".FPSCamera"]
				mire = scene.objects[self.controleur.nomEntite + ".Mire"]
				objetHit = camera.rayCastTo(mire, 500) #peut importe le range qu'on lui met, le raycastTo arete de voir l'object apres une certainte distance
				objetStr = str(objetHit)
				nomEntite = ""
				for cle, valeur in self.visualisationDict.items():
					if objetHit == valeur:
						nomEntite = cle
						
				notreEntite = self.visualisationDict[self.controleur.nomEntite].localPosition
				if nomEntite is "":
					print("Je ne suis rien")
				else:
					enemiEntite = self.visualisationDict[nomEntite].localPosition

					
					liste = self.controleur.modele.entites[self.controleur.nomEntite].calculDistance(nomEntite,str(notreEntite),str(enemiEntite))
					obj = self.controleur.modele.trouverEntite(self.controleur.nomEntite)# trouver l'entite 
					if obj.attaquer(self.controleur.modele.entites[self.controleur.nomEntite].arme , liste):# attaquer avec l'arme qu'on a entre les mains 
						self.controleur.ajoutMessage("Attack",info = str(objetStr)+";"+ str(self.controleur.modele.entites[self.controleur.nomEntite].arme.degats))

			## Position ##
			zoneBuffer = 1 #zone de buffer avant de considerer une rotation
			millieu = render.getWindowWidth() / 2
			positionSouris = mouse.position[0] * render.getWindowWidth()
			if positionSouris > millieu + zoneBuffer:
				self.cleEnCours.update(rtournerG = 1)
			elif positionSouris < millieu - zoneBuffer:
				self.cleEnCours.update(rtournerD = 1)
			#on remet la souris au centre
			render.setMousePosition(int (render.getWindowWidth()/2), int(render.getWindowHeight()/2))

	def boneTracking(self):
		cont = logic.getCurrentController()
		own = cont.owner
		if 'track' not in own:
			own['track'] = "ArMa"

		actu = cont.actuators[own['track']]
		cont.activate(actu)
		
	def cameraPosition(self):
		cont = logic.getCurrentController()
		scene = logic.getCurrentScene()
		ray = cont.sensors["Ray"]
		joueur = cont.owner
		playerCam = scene.objects[joueur.parent.name +".TPSCamera"]
		playerCam.worldPosition = ray.hitPosition
	
	def tirerAnimBalle(self, nouvellePos):
		obj = self.controleur.modele.trouverEntite(self.controleur.nomEntite)
		scene = logic.getCurrentScene()
		#[positionCam[0],positionCam[1],positionCam[2]]
		positionCam = scene.objects[self.controleur.nomEntite+".FPSCamera"].position
		balle = self.controleur.modele.creerEntite("Balle", position=[positionCam[0], positionCam[1], 2.3], rotation=obj.rotation, info=[nouvellePos[0],nouvellePos[1],nouvellePos[2]])
		self.creerObjet(balle.id, "Balle", balle.position, scale=[1,1,1], layer=1, rotation=obj.rotation)
		self.controleur.modele.listeBalles.append(balle)
		
	def detecter(self, nom):
		cont = logic.getCurrentController()
		scene = logic.getCurrentScene()
		radar = self.visualisationDict[nom].sensors["Radar"]
		objetsHit = radar.hitObjectList
		nomEntite = ""
		for i in objetsHit:
			objetHit = i
			for cle, valeur in self.visualisationDict.items():
				if objetHit == valeur:
					nomEntite = cle
		return nomEntite
		
	def verifierVie(self):
		#print(self.controleur.modele.entites[self.controleur.nomEntite].vie)
		'''
		listeDeSpawn = [0,0,0]
		listeDeSpawn.append(35,35,0)
		listeDeSpawn.append(135,135,0)
		listeDeSpawn.append(235,235,0)
		nombre = random.randint(0,2)
		print(nombre)
		'''
		if self.controleur.modele.entites[self.controleur.nomEntite].vie <=0:
			position=[35,35,1]
			self.teleporterObjet(self.controleur.nomEntite,position)#on met a jour la vue
			self.controleur.ajoutMessage("teleport",self.controleur.nomEntite)
			self.controleur.modele.entites[self.controleur.nomEntite].vie =100
